#include "ClientMsg.h"
#include "Log.h"
#include "TimeUtil.h"

#define IP "127.0.0.1"
#define PORT 10812


CClientMsg::CClientMsg()
    :m_iSeqID(0), m_iSocket(-1)
{
}

CClientMsg::~CClientMsg()
{
}


bool CClientMsg::Init()
{
    bool bFlag = CNetBase::Init();
    if (!bFlag)
    {
        LOG_ERR("net init fail.");
        return false;
    }

    int iRet = CNetBase::AddConnect(IP, PORT);
    if (iRet != 0)
    {
        LOG_ERR("add connect fail,ip:%s,port:%d", IP, PORT);
        return false;
    }

    return true;
}


bool CClientMsg::OnConnect(const int iSocket)
{
    if (!CNetBase::OnConnect(iSocket))
    {
        return false;
    }

    m_iSocket = iSocket;
    LOG_INFO("connect succeed.ip:%s, port:%d",IP, PORT);

    return true;
}


bool CClientMsg::OnClose(const int iSocket)
{
    if (!CNetBase::OnClose(iSocket))
    {
        return false;
    }

    m_iSocket = -1;

    return true;

}


bool CClientMsg::OnPacket(const int iSocket, char *pData, int iLen)
{
    if (iSocket == -1 )
    {
        LOG_ERR("socket is error. socket:%d", iSocket);
        return false;
    }
    if (pData == NULL)
    {
        LOG_ERR("data is null.socket:%d", iSocket);
        return false;
    }
    if (iLen <= 0)
    {
        LOG_ERR("data length is less or equel then 0. socket:%d, len:%d", iSocket, iLen);
        return false;
    }

    comm::Packet commPacket;
    if (!commPacket.ParseFromArray(pData, iLen))
    {
        LOG_ERR("parse   head fail.socket:%d, len:%d", iSocket, iLen);
        return false;
    }

    ResHandleMap::iterator mapResIt = m_mapResMsgHandleMap.find(commPacket.head().seqid());
    if (mapResIt != m_mapResMsgHandleMap.end())
    {
        int iRet = mapResIt->second.pfResHandle(commPacket.body());
        if (iRet != 0)
        {
            LOG_ERR("handle res message fail.return:%d", iRet);
        }
    
    }
    else
    {
        NotifyHandleMap::iterator mapNotifyIt = m_mapNotifyHandleVecMap.find(commPacket.head().cmd());
        if (mapNotifyIt != m_mapNotifyHandleVecMap.end())
        {
            if (mapNotifyIt->second.empty())
            {
                LOG_ERR("this is notify handle, but not any handle be registed.cmd:%d ", commPacket.head().cmd());
                return -1;
            }
            for (NotifyHandleVec::iterator vecIt = mapNotifyIt->second.begin(); vecIt != mapNotifyIt->second.end(); ++vecIt)
            {
                int iRet = (*vecIt)(commPacket.body());
                if (iRet != 0)
                {
                    LOG_ERR("handle res message fail.return:%d", iRet);
                }
            }
        }
        else
        {
            LOG_ERR("res and notify all don't handle this message.cmd:%d,seqid:%d",commPacket.head().cmd(), commPacket.head().seqid());
            return -1;
        }
    }

    return true;
}

int CClientMsg::SendMsg(const google::protobuf::Message &commPackage, CALLBACK_MSG_HANDLE pfMsgHandle)
{
    if (!IsConnected())
    {
        LOG_ERR("no connect.");
        return -1;
    }

    const comm::Packet *pPacket = dynamic_cast<const comm::Packet*>(&commPackage);
    if (pPacket == NULL)
    {
        LOG_ERR("packet dynamic cast fail.msg:%s", commPackage.DebugString().c_str());
        return -1;
    }

    int iSeqID = pPacket->head().seqid();
    int iRet = RegisResHandle(iSeqID, pfMsgHandle);
    if (iRet != 0)
    {
        LOG_ERR("regist fail.ret:%d,msg:%s",iRet, commPackage.DebugString().c_str());
        return iRet;
    }

    static char csDataBuffer[MAX_DATA_SIZE]; 
    if (!commPackage.SerializeToArray(csDataBuffer, sizeof(csDataBuffer)))
    {
        LOG_ERR("package serialize to array fail.size:%d,package:%s", MAX_DATA_SIZE, commPackage.DebugString().c_str());
        return -1;
    }

    iRet = Send(m_iSocket, csDataBuffer, commPackage.ByteSize());
    if (iRet != 0)
    {
        LOG_ERR("send fail.ret:%d,size:%d,msg:%s", iRet,commPackage.ByteSize(), commPackage.DebugString().c_str());
        return iRet;
    }


    return iRet;
}


int CClientMsg::SendMsg(comm::EnmModuleCmd eModule, int iCmd, const google::protobuf::Message &csBody,
    CALLBACK_MSG_HANDLE pfMsgHandle, int64_t llRoleID)
{
    if (!IsConnected())
    {
        LOG_ERR("no connect.");
        return -1;
    }

    comm::Head &pbHead = CreateHead(eModule, iCmd, llRoleID);

    comm::Packet pbPacket;
    pbPacket.mutable_head()->CopyFrom(pbHead);

    static char csDataBuffer[MAX_DATA_SIZE];
    if (!csBody.SerializeToArray(csDataBuffer, sizeof(csDataBuffer)))
    {
        LOG_ERR("body serialize to array fail.size:%d,body:%s",MAX_DATA_SIZE,csBody.DebugString().c_str());
        return -1;
    }
    pbPacket.set_body(string(csDataBuffer,csBody.ByteSize()));

    SendMsg(pbPacket, pfMsgHandle);
    return 0;
}


comm::Head& CClientMsg::CreateHead(comm::EnmModuleCmd enmModule, int iCmd, int64_t ullRoleID)
{
    static comm::Head pbHead;
    pbHead.Clear();
    pbHead.set_cmd(CreateCmd(enmModule, iCmd));
    pbHead.set_roleid(ullRoleID);
    pbHead.set_seqid(CreateSeq());

    return pbHead;
}


int CClientMsg::RegisResHandle(int iSeqID, CALLBACK_MSG_HANDLE pfResHandle)
{
    if (iSeqID <= 0)
    {
        LOG_ERR("can't regist seqid less then or equal 0. seqid:%d", iSeqID);
        return -1;
    }
    ResHandleMap::iterator mapIt = m_mapResMsgHandleMap.find(iSeqID);
    if (mapIt == m_mapResMsgHandleMap.end())
    {
        CallBackResHandle stCallBackResHandle;
        stCallBackResHandle.pfResHandle = pfResHandle;
        stCallBackResHandle.iRegistTime = CTimeUtil::GetCurSecond();
        if (!(m_mapResMsgHandleMap.insert(make_pair(iSeqID, stCallBackResHandle)).second))
        {
            LOG_ERR("insert fail.SeqID:%d", iSeqID);
            return -1;
        }
        return 0;
    }
    else
    {
        LOG_ERR("already regist.SeqID:%d", iSeqID);
        return -1;
    }
}

int CClientMsg::RegistNotifyHandle(int iCmd, CALLBACK_MSG_HANDLE pfNotifyHandle)
{
    NotifyHandleMap::iterator mapIt = m_mapNotifyHandleVecMap.find(iCmd);
    if(mapIt == m_mapNotifyHandleVecMap.end())
    {
        mapIt = m_mapNotifyHandleVecMap.insert(make_pair(iCmd, vector<CALLBACK_MSG_HANDLE>())).first;
        if (mapIt == m_mapNotifyHandleVecMap.end())
        {
            LOG_ERR("insert map failed.cmd:%d", iCmd);
            return -1;
        }
        mapIt->second.push_back(pfNotifyHandle);
        return 0;
    }

    for (vector<CALLBACK_MSG_HANDLE>::iterator vecIt = mapIt->second.begin(); vecIt != mapIt->second.end(); ++vecIt)
    {
        if ((*vecIt) == pfNotifyHandle)
        {
            LOG_ERR("already push back. cmd:%d", iCmd);
            return 0;
        }
    }
    mapIt->second.push_back(pfNotifyHandle);

    return 0;
}

int CClientMsg::UnRegistNotifyHandle(int iCmd, CALLBACK_MSG_HANDLE pfNotifyHandle)
{
    NotifyHandleMap::iterator mapIt = m_mapNotifyHandleVecMap.find(iCmd);
    if (mapIt == m_mapNotifyHandleVecMap.end())
    {
        LOG_ERR("not find handle.cmd:%d", iCmd);
        return 0;
    }

    int iCount = 0;
    for (vector<CALLBACK_MSG_HANDLE>::iterator vecIt = mapIt->second.begin(); vecIt != mapIt->second.end(); )
    {
        if (pfNotifyHandle == (*vecIt))
        {
            vecIt = mapIt->second.erase(vecIt);
            ++iCount;
            continue;
        }
        ++vecIt;
    }

    if (iCount <= 0)
    {
        LOG_ERR("there is not handle to remove.Cmd:%d", iCmd);
    }
    return iCount;
}

int CClientMsg::UnRegistNotifyHandleByCmd(int iCmd)
{
    NotifyHandleMap::iterator mapIt = m_mapNotifyHandleVecMap.find(iCmd);
    if (mapIt == m_mapNotifyHandleVecMap.end())
    {
        LOG_ERR("not find handle.cmd:%d", iCmd);
        return 0;
    }
    int iCount = mapIt->second.size();
    m_mapNotifyHandleVecMap.erase(iCmd);
    if (iCount <= 0)
    {
        LOG_ERR("there is not handle to remove.Cmd:%d", iCmd);
    }
    return iCount;
}

int CClientMsg::UnRegistNotifyHandleByHandle(CALLBACK_MSG_HANDLE pfNotifyHandle)
{
    NotifyHandleMap::iterator mapIt = m_mapNotifyHandleVecMap.begin();
    int iCount = 0;
    for (; mapIt != m_mapNotifyHandleVecMap.end(); ++mapIt)
    {
        for (vector<CALLBACK_MSG_HANDLE>::iterator vecIt = mapIt->second.begin(); vecIt != mapIt->second.end(); )
        {
            if (pfNotifyHandle == (*vecIt))
            {
                vecIt = mapIt->second.erase(vecIt);
                ++iCount;
                continue;
            }
            ++vecIt;
        }
    }

    if (iCount <= 0)
    {
        LOG_ERR("there is not handle to remove.");
    }
    return iCount;
}

comm::EnmModuleCmd CClientMsg::GetModuleFromCmd(int iCmd)
{
    int iModule = iCmd / 10000;
    if (comm::EnmModuleCmd_IsValid(iModule))
    {
        return (comm::EnmModuleCmd)iModule;
    }
    else
    {
        return comm::ENM_MODULE_ERROR;
    }
}
